package org.gdstash.db;

import org.gdstash.ui.GDStashFrame;

import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.LinkedList;
import java.util.List;

public class StatCriteriaCombination {
    private ItemCriteriaCombination itemCombo;
    private SelectionCriteria criteria;

    public StatCriteriaCombination(final SelectionCriteria criteria) {
        this.criteria = criteria;
        this.itemCombo = new ItemCriteriaCombination(criteria);
    }

    public StatCriteriaCombination(final SelectionCriteria criteria, final ItemCriteriaCombination combo) {
        this.criteria = criteria;
        this.itemCombo = combo;
    }

    public List<SelectionCriteria.StatInfo> getStatInfoList() {
        return this.criteria.statInfos;
    }

    public void setItemClass(final String itemClass) {
        this.itemCombo.setItemClass(itemClass);
    }

    public String determineItemParameters() {
        if (this.itemCombo == null) {
            return null;
        }
        return this.itemCombo.determineItemParameters();
    }

    public String determineItemIDStatement() {
        String command = "SELECT I.ITEM_ID FROM GD_ITEM I INNER JOIN GD_ITEM_STAT D ON I.ITEM_ID = S.ITEM_ID WHERE I.ITEM_CLASS = ?";
        if (this.itemCombo.usesItemRarity()) {
            command += " AND I.RARITY = ?";
        }
        if (this.itemCombo.usesArmorClass()) {
            command += " AND I.ARMOR_CLASS = ?";
        }
        if (this.itemCombo.usesArtifactClass()) {
            command += " AND I.ARTIFACT_CLASS = ?";
        }
        if (this.itemCombo.getMinLevel() != -1) {
            command += " AND I.REQ_LEVEL >= ?";
        }
        if (this.itemCombo.getMaxLevel() != -1) {
            command += " AND I.REQ_LEVEL <= ?";
        }
        if (this.itemCombo.getMaxCunning() != -1) {
            command += " AND I.REQ_DEX <= ?";
        }
        if (this.itemCombo.getMaxPhysique() != -1) {
            command += " AND I.REQ_STR <= ?";
        }
        if (this.itemCombo.getMaxSpirit() != -1) {
            command += " AND I.REQ_INT <= ?";
        }
        if (this.itemCombo.isNoEnemyOnly()) {
            command += " AND I.ENEMY_ONLY = ?";
        }
        command += this.itemCombo.determineSlotConditions("I.");
        command += " AND (S.STAT_TYPE = ? AND ((S.STAT_MIN > 0) OR (D.MODIFIER > 0)))";
        return command;
    }

    public String determineStashIDItemStatement(final boolean isHardcore) {
        String command = "SELECT S.STASH_ID FROM STASH_ITEM_V10 SI, GD_ITEM I, GD_ITEM_STAT S WHERE SI.ITEM_ID = I.ITEM_ID AND I.ITEM_ID = S.ITEM_ID AND I.ITEM_CLASS = ?";
        if (!GDStashFrame.iniConfig.sectRestrict.transferSCHC) {
            if (isHardcore) {
                command += " AND SI.HARDCORE = true";
            } else {
                command += " AND SI.HARDCORE = false";
            }
        }
        if (this.itemCombo.usesItemRarity()) {
            command += " AND I.RARITY = ?";
        }
        if (this.itemCombo.usesArmorClass()) {
            command += " AND I.ARMOR_CLASS = ?";
        }
        if (this.itemCombo.usesArtifactClass()) {
            command += " AND I.ARTIFACT_CLASS = ?";
        }
        if (this.itemCombo.getMinLevel() != -1) {
            command += " AND I.REQ_LEVEL >= ?";
        }
        if (this.itemCombo.getMaxLevel() != -1) {
            command += " AND I.REQ_LEVEL <= ?";
        }
        if (this.itemCombo.getMaxCunning() != -1) {
            command += " AND I.REQ_DEX <= ?";
        }
        if (this.itemCombo.getMaxPhysique() != -1) {
            command += " AND I.REQ_STR <= ?";
        }
        if (this.itemCombo.getMaxSpirit() != -1) {
            command += " AND I.REQ_INT <= ?";
        }
        if (this.itemCombo.isNoEnemyOnly()) {
            command += " AND I.ENEMY_ONLY = ?";
        }
        command += this.itemCombo.determineSlotConditions("I.");
        command += " AND (S.STAT_TYPE = ? AND ((S.STAT_MIN > 0) OR (S.MODIFIER > 0)))";
        return command;
    }

    public int fillItemIDStatement(final PreparedStatement ps) throws SQLException {
        if (this.criteria.statInfos == null) {
            return -1;
        }
        return this.itemCombo.fillItemStatement(ps);
    }

    public String determineStashIDPrefixStatement(final boolean isHardcore) {
        String command = "SELECT S.STASH_ID FROM STASH_ITEM_V10 SI, GD_ITEM I, GD_AFFIX A, GD_AFFIX_STAT S WHERE SI.ITEM_ID = I.ITEM_ID AND SI.PREFIX_ID = A.AFFIX_ID AND A.TYPE = 1 AND A.AFFIX_ID = S.AFFIX_ID AND I.ITEM_CLASS = ?";
        if (!GDStashFrame.iniConfig.sectRestrict.transferSCHC) {
            if (isHardcore) {
                command += " AND SI.HARDCORE = true";
            } else {
                command += " AND SI.HARDCORE = false";
            }
        }
        if (this.itemCombo.usesArmorClass()) {
            command += " AND I.ARMOR_CLASS = ?";
        }
        if (this.itemCombo.usesArtifactClass()) {
            command += " AND I.ARTIFACT_CLASS = ?";
        }
        if (this.itemCombo.getMaxLevel() != -1) {
            command += " AND I.REQ_LEVEL <= ?";
        }
        if (this.itemCombo.getMaxCunning() != -1) {
            command += " AND I.REQ_DEX <= ?";
        }
        if (this.itemCombo.getMaxPhysique() != -1) {
            command += " AND I.REQ_STR <= ?";
        }
        if (this.itemCombo.getMaxSpirit() != -1) {
            command += " AND I.REQ_INT <= ?";
        }
        if (this.itemCombo.isNoEnemyOnly()) {
            command += " AND I.ENEMY_ONLY = ?";
        }
        if (this.itemCombo.usesItemRarity()) {
            command += " AND A.RARITY = ?";
        }
        if (this.itemCombo.getMinLevel() != -1) {
            command += " AND A.REQ_LEVEL >= ?";
        }
        if (this.itemCombo.getMaxLevel() != -1) {
            command += " AND A.REQ_LEVEL <= ?";
        }
        command += this.itemCombo.determineSlotConditions("I.");
        command += " AND (S.STAT_TYPE = ? AND ((S.STAT_MIN > 0) OR (S.MODIFIER > 0)))";
        return command;
    }

    public String determineStashIDSuffixStatement(final boolean isHardcore) {
        String command = "SELECT S.STASH_ID FROM STASH_ITEM_V10 SI, GD_ITEM I, GD_AFFIX A, GD_AFFIX_STAT S WHERE SI.ITEM_ID = I.ITEM_ID AND SI.SUFFIX_ID = A.AFFIX_ID AND A.TYPE = 2 AND A.AFFIX_ID = S.AFFIX_ID AND I.ITEM_CLASS = ?";
        if (!GDStashFrame.iniConfig.sectRestrict.transferSCHC) {
            if (isHardcore) {
                command += " AND SI.HARDCORE = true";
            } else {
                command += " AND SI.HARDCORE = false";
            }
        }
        if (this.itemCombo.usesArmorClass()) {
            command += " AND I.ARMOR_CLASS = ?";
        }
        if (this.itemCombo.usesArtifactClass()) {
            command += " AND I.ARTIFACT_CLASS = ?";
        }
        if (this.itemCombo.getMaxLevel() != -1) {
            command += " AND I.REQ_LEVEL <= ?";
        }
        if (this.itemCombo.getMaxCunning() != -1) {
            command += " AND I.REQ_DEX <= ?";
        }
        if (this.itemCombo.getMaxPhysique() != -1) {
            command += " AND I.REQ_STR <= ?";
        }
        if (this.itemCombo.getMaxSpirit() != -1) {
            command += " AND I.REQ_INT <= ?";
        }
        if (this.itemCombo.isNoEnemyOnly()) {
            command += " AND I.ENEMY_ONLY = ?";
        }
        if (this.itemCombo.usesItemRarity()) {
            command += " AND A.RARITY = ?";
        }
        if (this.itemCombo.getMinLevel() != -1) {
            command += " AND A.REQ_LEVEL >= ?";
        }
        if (this.itemCombo.getMaxLevel() != -1) {
            command += " AND A.REQ_LEVEL <= ?";
        }
        command += this.itemCombo.determineSlotConditions("I.");
        command += " AND (S.STAT_TYPE = ? AND ((S.STAT_MIN > 0) OR (S.MODIFIER > 0)))";
        return command;
    }

    public int fillAffixIDStatement(final PreparedStatement ps) throws SQLException {
        if (this.criteria.statInfos == null) {
            return -1;
        }
        ps.clearParameters();
        int nextPos = 1;
        ps.setString(nextPos, this.itemCombo.getItemClass());
        ++nextPos;
        if (this.itemCombo.usesArmorClass()) {
            ps.setString(nextPos, this.itemCombo.getArmorClass());
            ++nextPos;
        }
        if (this.itemCombo.usesArtifactClass()) {
            ps.setString(nextPos, this.itemCombo.getArtifactClass());
            ++nextPos;
        }
        if (this.itemCombo.getMaxLevel() != -1) {
            ps.setInt(nextPos, this.itemCombo.getMaxLevel());
            ++nextPos;
        }
        if (this.itemCombo.getMaxCunning() != -1) {
            ps.setInt(nextPos, this.itemCombo.getMaxCunning());
            ++nextPos;
        }
        if (this.itemCombo.getMaxPhysique() != -1) {
            ps.setInt(nextPos, this.itemCombo.getMaxPhysique());
            ++nextPos;
        }
        if (this.itemCombo.getMaxSpirit() != -1) {
            ps.setInt(nextPos, this.itemCombo.getMaxSpirit());
            ++nextPos;
        }
        if (this.itemCombo.isNoEnemyOnly()) {
            ps.setBoolean(nextPos, false);
            ++nextPos;
        }
        if (this.itemCombo.usesItemRarity()) {
            ps.setString(nextPos, this.itemCombo.getItemRarity());
            ++nextPos;
        }
        if (this.itemCombo.getMinLevel() != -1) {
            ps.setInt(nextPos, this.itemCombo.getMinLevel());
            ++nextPos;
        }
        if (this.itemCombo.getMaxLevel() != -1) {
            ps.setInt(nextPos, this.itemCombo.getMaxLevel());
            ++nextPos;
        }
        return nextPos;
    }

    public List<StatCriteriaCombination> createItemStatCombinations() {
        final List<StatCriteriaCombination> list = new LinkedList<StatCriteriaCombination>();
        for (final String itemClass : this.criteria.itemClass) {
            this.itemCombo.setItemClass(itemClass);
            final List<ItemCriteriaCombination> itemCombos = this.itemCombo.createItemCombinations();
            for (final ItemCriteriaCombination combo : itemCombos) {
                final StatCriteriaCombination scc = new StatCriteriaCombination(this.criteria, combo);
                list.add(scc);
            }
        }
        return list;
    }

    public List<StatCriteriaCombination> createAffixStatCombinations() {
        final List<StatCriteriaCombination> list = new LinkedList<StatCriteriaCombination>();
        for (final String itemClass : this.criteria.itemClass) {
            this.itemCombo.setItemClass(itemClass);
            final List<ItemCriteriaCombination> itemCombos = this.itemCombo.createAffixCombinations();
            for (final ItemCriteriaCombination combo : itemCombos) {
                final StatCriteriaCombination scc = new StatCriteriaCombination(this.criteria, combo);
                list.add(scc);
            }
        }
        return list;
    }
}
